//
//  CZRefreshControl.swift
//  Weibo
//
//  Created by cc on 10/26/17.
//  Copyright © 2017 cc. All rights reserved.
//

import UIKit


/// 刷新狀態切換的臨界點
private let CZRefreshOffset: CGFloat = 126

/// 刷新狀態
///
/// - Normal: 普通狀態
/// - Pulling: 超過臨界點，如果放手開始刷新
/// - WillRefresh: 用戶超過臨界點，並且放手
enum CZRefreshState {
    case Normal
    case Pulling
    case WillRefresh
}


/// 刷新控件 - 負責刷新相關的邏輯處理
class CZRefreshControl: UIControl {
    
    // MARK: -屬性
    //刷新控件的父視圖，下拉刷新控件應該适用於 UITableView / UICollectionView
    private weak var scrollView: UIScrollView?
    //刷新視圖
    private lazy var refreshView: CZRefreshView = CZRefreshView.refreshView()
    
    
    //MARK: - 構造函數
    init() {
        super.init(frame: CGRect())
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupUI()
    }
    
    
    
    /*
         willMove addSubView 方法會調用
         - 當添加到父視圖時， newSuperview是父視圖
         - 當父視圖被移除，newSuperview是nil
     */
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        
        //判斷父視圖的類型
        guard let sv = newSuperview as? UIScrollView else{
            return
        }
          //記錄父視圖
        scrollView = sv
        
        //KVO 監聽父視圖的 contentOffset
        scrollView?.addObserver(self, forKeyPath: "contentOffset", options: [], context: nil)
        
    }
    
    //本視圖從父視圖上移除
    //提示：所有的下拉刷新構架都是監聽父視圖的 contentOffset
    override func removeFromSuperview() {
        
        super.removeObserver(self, forKeyPath: "contentOffset")
        super.removeFromSuperview()
        
    }
    
    
    //所有KVO方法會統一調用此方法
    //在程序中，通常只監聽某一個對象的某幾個屬性，如果屬性太多方法會很亂
    //觀察者模型，在不需要的時候都要釋放
    // -通知中心 ： 如果不釋放，什麼也不發生，但有內存泄漏，會有多次註冊的可能
    // - KVO： 如果不釋放，會崩潰
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        
        guard let sv = scrollView else {
            return
        }
        // 初始高度是0
        let height = -(sv.contentInset.top + sv.contentOffset.y)
        
        if height < 0 {
            return
        }
        
        //可以根據高度設置刷新控件的frame
        self.frame = CGRect(x: 0, y: -height, width: sv.bounds.width, height: height)
        
        //傳遞父視圖高度,如果正大刷新中，不传递
        if refreshView.refreshState != .WillRefresh {
            refreshView.parentViewHeight = height
        }
        
        // 判断临界点 - 只需判断一次
        if sv.isDragging {
            
            if height > CZRefreshOffset && (refreshView.refreshState == .Normal) {
                refreshView.refreshState = .Pulling
                print("放手刷新")
            } else if height <= CZRefreshOffset && (refreshView.refreshState == .Pulling) {
                refreshView.refreshState = .Normal
                print("繼續使劲")
            }
            
        } else {
            // 放手 - 判断是否超过临界点
            if refreshView.refreshState == .Pulling {
                print("準備開始刷新")

                beginRefreshing()
                
                //發送刷新數據事件
                sendActions(for: .valueChanged)
            }
            
        }
    }
    
    
    /// 開始刷新
    func beginRefreshing() {
     
        //判斷父視圖
        guard let sv = scrollView else {
            return
        }
        
        //判斷是否正在刷新，如果正在刷新，直接返回
        if refreshView.refreshState == .WillRefresh {
            return
        }
        
        //設置刷新視圖狀態
        refreshView.refreshState = .WillRefresh
        
        //調整表格的間隔
        var inset = sv.contentInset
        inset.top += CZRefreshOffset
        
        sv.contentInset = inset
        
        
        //設置刷新視圖的父視圖高度
        refreshView.parentViewHeight = CZRefreshOffset
        
    }
    
    
    /// 結束刷新
    func endRefreshing() {
        
        guard let sv = scrollView else {
            return
        }
        
        //判斷狀態， 是否正在刷新，如果不是，直接返回
        if refreshView.refreshState != .WillRefresh {
            return
        }
        
        //恢復刷新視圖的狀態
        refreshView.refreshState = .Normal
        
        //恢復表格視圖的contentInset
        var inset = sv.contentInset
        inset.top -= CZRefreshOffset
        sv.contentInset = inset
        
    }
}



extension CZRefreshControl {
    private func setupUI () {
        backgroundColor = superview?.backgroundColor
        
        //設置超出邊界不顯示
//        clipsToBounds = true
        
        //添加刷新視圖
        addSubview(refreshView)
        
        //自動佈局 - 設置xib控件的自動佈局,需要指定寬高約束
        refreshView.translatesAutoresizingMaskIntoConstraints = false
        
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0))

        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0))

        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: refreshView.bounds.width))

        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: refreshView.bounds.height))
    }
}
